openCv page Dewarp 책 반으로 자르기

개요

기존 소스는 책의 이미지가 반으로 잘린 것을 기준으로 동작하였습니다.

이번 포스팅에서는 책의 이미지를 반으로 자르는 것을 구현하는 것에 대해서 설명하겠습니다.

책 반으로 자르기

구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def cut_half(img):
height, width = img.shape[:2]
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
edges = cv2.Canny(gray,50,150,apertureSize = 3)
# 선을 추출
lines = cv2.HoughLinesP(edges,1,np.pi/180,100, minLineLength=80, maxLineGap=5)
tmp_candy = []
tmp_abs = []
for i in range(len(lines)):
for x1,y1,x2,y2 in lines[i]:
gapY = np.abs(y2-y1)
gapX = np.abs(x2-x1)
# 선의 x축의 차이가 5이하 y축의 차이가 10이상이면 세로줄로 판별
if gapX < 5 and gapY > 50 :
tmp_candy.append(x1)
tmp_abs.append(np.abs(x1- width//2))

left_img = img[0:height,0:tmp_candy[np.argmin(tmp_abs)]]
right_img = img[0:height,tmp_candy[np.argmin(tmp_abs)]+1:width]

return left_img, right_img

입력으로 이미지를 받은 후 HoughLinesP함수를 통해 선을 추출한 후 세로선을 판별,

이미지 중간점에 가장 가까운 세로선을 선택해 자르는 내용입니다.

전처리

1
2
3
height, width = img.shape[:2]
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
edges = cv2.Canny(gray,50,150,apertureSize = 3)

기존의 이미지에서 높이와 넓이를 구합니다. 이는 나중에 자를때 기준을 정하기 위해서 사용됩니다.

cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)를 통해 이미지를 회색조로 변경 합니다.

중간을 자르기 위한 세로선을 찾기 위해서 Canny로 이미지를 변경합니다.

cv2.Canny

세로 선 찾기

1
2
3
4
5
6
7
8
9
10
11
lines = cv2.HoughLinesP(edges,1,np.pi/180,100, minLineLength=80, maxLineGap=5)
tmp_candy = []
tmp_abs = []
for i in range(len(lines)):
for x1,y1,x2,y2 in lines[i]:
gapY = np.abs(y2-y1)
gapX = np.abs(x2-x1)
# 선의 x축의 차이가 5이하 y축의 차이가 10이상이면 세로줄로 판별
if gapX < 5 and gapY > 50 :
tmp_candy.append(x1)
tmp_abs.append(np.abs(x1- width//2))

openCV에서 선을 찾기 위한 함수인 허프변환 cv2.HoughLines() , cv2.HoughLinesP()이 있습니다. 그중 확률적으로 선을 찾는 함수인 허프 변환 HoughLinesP을 사용하였습니다.

  • cv2.HoughLinesP(image, rho, theta, threshold, minLineLength, maxLineGap) → lines
    • image – 8bit, single-channel binary image, canny edge를 선 적용.
    • rho – r 값의 범위 (0 ~ 1 실수)
    • theta – 𝜃 값의 범위(0 ~ 180 정수)
    • threshold – 만나는 점의 기준, 숫자가 작으면 많은 선이 검출되지만 정확도가 떨어지고, 숫자가 크면 정확도가 올라감.
    • minLineLength – 선의 최소 길이. 이 값보다 작으면 reject.
    • maxLineGap – 선과 선사이의 최대 허용간격. 이 값보다 작으며 reject.

HoughLinesP의 결과는 두점의 좌표로 리턴됩니다. 두점을 이으면 선이 됩니다.

찾은 선의 이미지

세로선인 것을 찾기 위해서는 간단히 두 점의 x축 차이는 매우 작고 y축 차이는 매우 크면됩니다.

두점의 좌표 차이를 구하기 위해서 절대값을 구하는 함수인 np.abs을 사용하였습니다.

제가 사용한 기준은 x축의 차이는 5픽셀 이하이고 y축의 차이는 50이상으로 잡았습니다.

또한 우리의 목표는 책을 반으로 자르는 것이기 때문에 해당 선의 x좌표가 이미지의 중간에 얼마나 근접해 있는지를 체크하였습니다.

최종 책 이미지 자르기

1
2
3
4
left_img = img[0:height,0:tmp_candy[np.argmin(tmp_abs)]]
right_img = img[0:height,tmp_candy[np.argmin(tmp_abs)]+1:width]

return left_img, right_img

책의 좌우를 자르기 위해서 높이는 0부터 기존 이미지의 높이만큼을 할당하였습니다.

넓이는 왼쪽은 0부터 위에서 구한 세로선중 이미지의 가운데와 가장 근접한 선의 인덱스를 np.argmin(tmp_abs)로 찾았습니다.

np.argmin은 입력된 리스트에서 가장 작은 값의 인덱스를 리턴하는 함수입니다.

이 알고리즘의 핵심은 세로줄 찾기와 책의 중간은 이미지 중간과 가장 근접한 세로줄로 표현된다 입니다.

공유하기